package org.xx.armory.spring5.security;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ansi.AnsiColor;
import org.springframework.boot.ansi.AnsiOutput;
import org.springframework.boot.ansi.AnsiStyle;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.xx.armory.commons.ForLogging;

import java.util.Collection;

import static org.apache.commons.lang3.StringUtils.trimToEmpty;
import static org.springframework.security.core.authority.AuthorityUtils.createAuthorityList;
import static org.xx.armory.commons.SysUtils.uniqueHash8;
import static org.xx.armory.spring5.security.WebSecurityConfig.ROLE_ADMIN;
import static org.xx.armory.spring5.security.WebSecurityConfig.USER_ADMIN;

/**
 * 验证内置管理员帐户的验证器。
 */
public class AdminAuthenticationProvider
        extends AbstractArmoryUserPasswordAuthenticationProvider
        implements AuthenticationProvider, InitializingBean {
    private static final String PWD_ENV = "ARMORY_ADMIN_PWD";

    @ForLogging
    private final Logger logger = LoggerFactory.getLogger(AdminAuthenticationProvider.class);

    @Value("${armory.security.admin.enabled:true}")
    private boolean enabled;

    private String pwd;

    @Override
    protected Collection<? extends GrantedAuthority> authenticate(
            String username,
            CharSequence password,
            ArmoryWebAuthenticationDetails details
    )
            throws AuthenticationException {
        if (!username.equalsIgnoreCase(USER_ADMIN)) {
            return null;
        }

        if (!this.enabled) {
            throw new LockedException("User \"" + USER_ADMIN + "\" disabled");
        }

        if (!this.pwd.contentEquals(password)) {
            throw new BadCredentialsException("Password mismatched");
        }

        return createAuthorityList(ROLE_ADMIN);
    }

    @Override
    public void afterPropertiesSet()
            throws Exception {
        if (!this.enabled) {
            logger.info("User \"{}\" disabled", USER_ADMIN);
            return;
        }

        final var envpwd = trimToEmpty(System.getenv(PWD_ENV));
        if (!envpwd.isEmpty()) {
            System.out.println(AnsiOutput.toString(
                    AnsiColor.BRIGHT_CYAN, AnsiStyle.BOLD,
                    "LOAD PASSWORD OF ",
                    AnsiColor.BRIGHT_WHITE,
                    USER_ADMIN,
                    AnsiColor.BRIGHT_CYAN,
                    " FROM ENVIRONMENT ",
                    AnsiColor.BRIGHT_MAGENTA,
                    PWD_ENV
            ));
            this.pwd = envpwd;
        } else {
            // 密码被设置为空白，需要自动生成一个随机密码。
            final var r1 = Math.random();
            final var r2 = Math.random();
            final var r3 = Math.random();
            final var hash = uniqueHash8(new Object[]{r1, r2, r3});
            System.out.println(AnsiOutput.toString(
                    AnsiColor.BRIGHT_CYAN, AnsiStyle.BOLD,
                    "GENERATED PASSWORD OF ",
                    AnsiColor.BRIGHT_WHITE,
                    USER_ADMIN,
                    AnsiColor.BRIGHT_CYAN,
                    " : ",
                    AnsiColor.BRIGHT_MAGENTA,
                    hash));
            System.out.println();
            this.pwd = hash;
        }
    }
}
